package pl.elka.simulator.core.mobilityManager.impl;

import java.util.ArrayList;
import java.util.List;

import pl.elka.simulator.core.AreaConstraint;
import pl.elka.simulator.core.CollisionSolver;
import pl.elka.simulator.core.Constraint;
import pl.elka.simulator.core.EnviromentConfiguration;
import pl.elka.simulator.core.IPaintable;
import pl.elka.simulator.core.Node;
import pl.elka.simulator.core.Position;
import pl.elka.simulator.core.Treasure;
import pl.elka.simulator.core.configurationCommand.ConfigurationCommandType;
import pl.elka.simulator.core.configurationCommand.ables.IAbleToConstraintConfiguration;
import pl.elka.simulator.core.configurationCommand.ables.IAbleToNodeConfiguration;
import pl.elka.simulator.core.configurationCommand.ables.IAbleToTreasureConfiguration;
import pl.elka.simulator.core.mobilityManager.IMobilityManager;
import pl.elka.simulator.core.mobilityManager.MobilityManagerType;
import pl.elka.simulator.core.mobilityManager.impl.nodes.RWMNode;

public class RandomWalkMobilityManager implements IMobilityManager{

	private String id;
	
	
	public static final int MAX_CHANGE_VELOCITY_INTERVAL = 100;
	public static final int MIN_CHANGE_VELOCITY_INTERVAL = 10;
	//private static final float MIN_VELOCITY = 0.00001f;
	
	
	@Override
	public IMobilityManager newInstance() {		
		return new RandomWalkMobilityManager();
	}

	@Override
	public MobilityManagerType getType() {
		return MobilityManagerType.RandomWalkMobility;
	}

	@Override
	public List<ConfigurationCommandType> getAllowedConfigurationCommands() {
		List<ConfigurationCommandType> ret = new ArrayList<ConfigurationCommandType>();		
		return ret;
	}		

	@Override
	public void setId(String id) {		
		this.id = id;
	}

	@Override
	public String getId() {
		return id;
	}

	@Override
	public List<IPaintable> getPaintaibleElements() {
		List<IPaintable> ret = new ArrayList<IPaintable>();		
		if(nodes!=null){
			for(RWMNode n:nodes){
				ret.add(n.getPath());
			}
		}
		return ret;
	}
	
	protected List<RWMNode> nodes;
	protected List<Constraint> constraints;
	protected AreaConstraint areaConstraint;
	protected CollisionSolver collisionSolver;

	@Override
	public void applyEnviroment(EnviromentConfiguration cfg) {		
		nodes = new ArrayList<RWMNode>();
		
		for(Node n : cfg.getNodes()){
			RWMNode rwmNode = new RWMNode(randomInterval(n), 0, randomVelocity(n), (Position)n.getPosition().clone());
			nodes.add(rwmNode);
			rwmNode.path.addPathElement(rwmNode.position.clone());
		}	
		constraints = cfg.getConstraints();
		areaConstraint = cfg.getAreaConstraint();
		
		collisionSolver = new CollisionSolver(cfg);
	}	
	@Override
	public void makeMove(long elapsedTime) {		
		for(RWMNode node:nodes){
			//wyznaczam nowa pozycje wezla
			Position newPosition = new Position(
						node.position.x + node.currentVelocity.x*elapsedTime,
						node.position.y+node.currentVelocity.y*elapsedTime
					);
			
			//sprawdzam, czy wezel, przy pokonywaniu drogi nie wpadnie na ograniczenie
			Position collisionPosition = collisionSolver.findCollisionPosition(node.position, newPosition);
			
			//jesli wpasl na ograniczenie, to ustawiam go przy nim i wymuszam zniame predkosci
			if(collisionPosition!=null){
				node.position = collisionPosition;
				node.lastVelocityChangeInterval=node.velocityChangeInterval;
				//System.out.println("kolizja");
			}	
			//jesli nie wpadl, to po prostu go przestawiam
			else{
				node.position = newPosition;
				node.lastVelocityChangeInterval+=elapsedTime;
			}
			
			if(node.lastVelocityChangeInterval>=node.velocityChangeInterval){
				node.lastVelocityChangeInterval = 0;				
				node.currentVelocity = randomVelocity(node);
			}
			node.path.addPathElement(node.position.clone());
			
		}
	}
	protected int randomInterval(Node n){
		return 10;//return (int)(Math.random()*MAX_CHANGE_VELOCITY_INTERVAL+MIN_CHANGE_VELOCITY_INTERVAL);
	}
	protected Position randomVelocity(Node n){
		float xv =  (float)(Math.random()-0.5);
		float yv =  (float)(Math.random()-0.5);
		Position ret =  new Position(xv,yv);
		ret.setMagnitude(Node.MAX_VELOCITY);
		return ret;		
	}
	public List<RWMNode> getNodes(){
		return nodes;
	}
	@Override
	public void clear() {
		nodes = null;
	}
}
